home *** CD-ROM | disk | FTP | other *** search
/ 17 Bit Software 3: The Continuation / 17-Bit_The_Continuation_Disc.iso / amigan / amigan 3 / amiga / ckitio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-27  |  24.0 KB  |  1,142 lines

  1. char *ckxv = "Amiga tty I/O, 4D(004), 17 July 86";
  2.  
  3. /*  C K I T I O  --  Serial and Console I/O support for the Amiga */
  4.  
  5. /*
  6.  Author: Jack Rouse
  7.  Based on the CKUTIO.C module for Unix
  8.  Contributed to Columbia University for inclusion in C-Kermit.
  9.  Copyright (C) 1986, Jack J. Rouse, 106 Rubin Ct. Apt. A-4, Cary NC 27511
  10.  Permission is granted to any individual or institution to use, copy, or
  11.  redistribute this software so long as it is not sold for profit, provided this
  12.  copyright notice is retained. 
  13. */
  14.  
  15. #include <stdio.h>        /* standard I/O stuff */
  16. #undef NULL
  17. #include "exec/types.h"
  18. #include "exec/exec.h"
  19. #include "devices/serial.h"
  20. #include "devices/timer.h"
  21. #include "libraries/dos.h"
  22. #include "libraries/dosextens.h"
  23. #define fh_Interact fh_Port
  24. #define fh_Process fh_Type
  25. #include "intuition/intuition.h"
  26. #include "intuition/intuitionbase.h"
  27. #define BREAKSIGS (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D)
  28. #ifdef LAT304
  29. #include "lattice/fcntl.h"
  30. #include "lattice/signal.h"
  31. #endif
  32. #include "lattice/ios1.h"    /* defines ufbs structure */
  33.  
  34. char *ckxsys = " Commodore Amiga";    /* system name */
  35.  
  36. /* external declarations */
  37. extern int speed, mdmtyp, parity, flow;
  38.  
  39. /* external definitions */
  40. char *dftty = SERIALNAME;        /* serial device name */
  41. int dfloc = 1;                /* serial line is external */
  42. int dfprty = 0;                /* default parity is none */
  43. int dfflow = 1;                /* default flow control is on */
  44. int backgrd = 0;            /* default to foreground */
  45. int ckxech = 0;                /* echo in case redirected stdin */
  46.  
  47. struct Process *CurProc;        /* current process */
  48. struct CommandLineInterface *CurCLI;    /* current CLI info */
  49. extern struct IntuitionBase *IntuitionBase;    /* ptr to Intuition lib */
  50.  
  51. /* static definitions */
  52. static struct MsgPort *serport;        /* message port for serial comm */
  53. static struct MsgPort *conport;        /* console packet port */
  54. static struct timerequest *TimerIOB;    /* timer request */
  55. static struct IOExtSer *ReadIOB;    /* serial input request */
  56. static struct IOExtSer *WriteIOB;    /* serial output request */
  57. static struct DosPacket *conpkt;    /* console I/O packet */
  58. static WORD serialopen;            /* true iff serial device open */
  59. static WORD timeropen;            /* true iff timer device open */
  60. static WORD pendwrite;            /* true iff WriteIOB in use */
  61. static WORD pendread;            /* true iff ReadIOB in use */
  62. static WORD pendconsole;        /* true when console read pending */
  63. static int queuedser;            /* serial pushback char or -1 */
  64. static UBYTE serbufc;            /* char buffer for read ahead I/O */
  65. #define NTTOQ 64            /* connect output queue size */
  66. static char ttoq[NTTOQ];        /* connect output queue */
  67. static int nttoq;            /* number of chars in ttoq */
  68. static int pttoq;            /* next char to output in ttoq */
  69. static int queuedcon;            /* contti pushback char or -1 */
  70. static LONG intsigs;            /* signals for aborting serial I/O */
  71. static int (*inthdlr)();        /* function to signal break to */
  72. static BPTR rawcon;            /* file handle for RAW: window */
  73. static BPTR saverr;                     /* saved stderr file handle */
  74. static APTR savewindow;            /* saved process WindowPtr */
  75. static APTR pushwindow;            /* pushed process WindowPtr */
  76. static struct DateStamp prevtime;    /* saved time value */
  77.  
  78. /* Exec routines */
  79. APTR AllocMem();
  80. LONG AllocSignal();
  81. struct IORequest *CheckIO();
  82. VOID CloseDevice(), CloseLibrary();
  83. LONG DoIO();
  84. struct MsgPort *FindPort();
  85. struct Task *FindTask();
  86. VOID FreeMem(), FreeSignal();
  87. struct Message *GetMsg();
  88. LONG OpenDevice();
  89. struct Library *OpenLibrary();
  90. VOID PutMsg(), ReplyMsg();
  91. VOID SendIO();
  92. LONG SetSignal();
  93. VOID Signal();
  94. LONG Wait();
  95. LONG WaitIO();
  96. struct Message *WaitPort();
  97.  
  98. /* Exec support */
  99. struct IORequest *CreateExtIO();
  100. VOID DeleteExtIO();
  101. struct MsgPort *CreatePort();
  102. VOID DeletePort();
  103. struct Task *CreateTask();
  104. VOID DeleteTask();
  105.  
  106. /* AmigaDOS routines */
  107. VOID Delay();
  108. BPTR Open();
  109. VOID Close();
  110. BPTR Input(), Output();
  111. LONG Read();
  112. LONG WaitForChar();
  113. struct DateStamp *DateStamp();
  114.  
  115. /* AmigaDOS support (from ckiutl.c) */
  116. struct DosPacket *CreatePacket();
  117. VOID DeletePacket();
  118.  
  119. #ifdef LAT304
  120. /* translate Unix file handle (0, 1, or 2) to AmigaDOS file handle */
  121. #define DOSFH(n) fileno(&_iob[n])
  122. /* translate Unix file handle (0, 1, or 2) to Lattice file handle */
  123. #define FILENO(n) fileno(&_iob[n])
  124. #else
  125. /* Lattice runtime externals */
  126. extern struct UFB _ufbs[];
  127. extern int Enable_Abort;
  128. #define DOSFH(n) (_ufbs[n].ufbfh)
  129. #define FILENO(n) (n)
  130. #endif
  131.  
  132. /*
  133.  * make note of a serial error and quit
  134.  */
  135. static Fail(msg)
  136. char *msg;
  137. {
  138.     syscleanup();
  139.     fprintf(stderr, msg);
  140.     fprintf(stderr, "\n");
  141.     exit(2);
  142. }
  143. /*
  144.  * default interrupt handler
  145.  */
  146. static int defhdlr()
  147. {
  148.     printf("*** BREAK ***\n");
  149.     doexit(1);
  150. }
  151.  
  152. /*
  153.  *  sysinit -- Amiga specific initialization
  154.  */
  155. sysinit()
  156. {
  157.     register struct IOExtSer *iob;
  158.  
  159.     /* set current process info */
  160.     CurProc = (struct Process *)FindTask((char *)NULL);
  161.     CurCLI = (struct CommandLineInterface *)BADDR(CurProc->pr_CLI);
  162.     backgrd = (CurCLI == NULL || CurCLI->cli_Background);
  163.     savewindow = CurProc->pr_WindowPtr;
  164.  
  165.     /* default interrupts to exit handler */
  166.     intsigs = BREAKSIGS;
  167.     inthdlr = defhdlr;
  168. #ifdef LAT304
  169.     signal(SIGINT, SIG_IGN);
  170. #else
  171.     Enable_Abort = 0;
  172. #endif
  173.  
  174.     /* allocate console ports and IO blocks */
  175.     if ((conport = CreatePort((char *)NULL, 0L)) == NULL)
  176.         Fail("no console MsgPort");
  177.     if ((conpkt = CreatePacket()) == NULL)
  178.         Fail("no console packet");
  179.  
  180.     /* allocate serial ports and IO blocks */
  181.     if ((serport = CreatePort((char *)NULL, 0L)) == NULL)
  182.         Fail("no serial MsgPort");
  183.     iob = (struct IOExtSer *)CreateExtIO(serport,(LONG)sizeof(*iob));
  184.     if ((WriteIOB = iob) == NULL) Fail("no WriteIOB");
  185.     iob = (struct IOExtSer *)CreateExtIO(serport,(LONG)sizeof(*iob));
  186.     if ((ReadIOB = iob) == NULL) Fail("no ReadIOB");
  187.  
  188.     /* open the timer device */
  189.     TimerIOB = (struct timerequest *)
  190.            CreateExtIO(serport,(LONG)sizeof(*TimerIOB));
  191.     if (TimerIOB == NULL) Fail("no TimerIOB");
  192.     if (OpenDevice(TIMERNAME, (LONG)UNIT_VBLANK, TimerIOB, 0L) != 0)
  193.         Fail("no timer device");
  194.     timeropen = TRUE;
  195.  
  196.     /* open the Intuition library */
  197.     if (!IntuitionBase &&
  198.         (IntuitionBase = (struct IntuitionBase *)
  199.                  OpenLibrary("intuition.library", 0L) ) == NULL )
  200.         Fail("can't open Intuition");
  201.  
  202.     /* open the serial device to get configuration */
  203.     iob->io_SerFlags = SERF_SHARED;
  204.     if (OpenDevice(SERIALNAME, 0L, iob, 0L) != 0)
  205.         Fail("can't open serial.device");
  206.     /* set parameters from system defaults */
  207.     flow   = !(iob->io_SerFlags & SERF_XDISABLED);
  208.     parity = !(iob->io_SerFlags & SERF_PARTY_ON) ? 0 :
  209.          (iob->io_SerFlags & SERF_PARTY_ODD) ? 'o' : 'e';
  210.     speed  = iob->io_Baud;
  211.     mdmtyp = (iob->io_SerFlags & SERF_7WIRE) != 0;
  212.  
  213.     CloseDevice(iob);
  214.     serialopen = FALSE;
  215. }
  216.  
  217. /*
  218.  * syscleanup -- Amiga specific cleanup
  219.  */
  220. syscleanup()
  221. {
  222.     /* close everything */
  223.     if (serialopen) CloseDevice(ReadIOB);
  224.     if (timeropen) CloseDevice(TimerIOB);
  225.     if (TimerIOB) DeleteExtIO(TimerIOB, (LONG)sizeof(*TimerIOB));
  226.     if (WriteIOB) DeleteExtIO(WriteIOB, (LONG)sizeof(*WriteIOB));
  227.     if (ReadIOB) DeleteExtIO(ReadIOB, (LONG)sizeof(*ReadIOB));
  228.     if (serport) DeletePort(serport);
  229.     if (conpkt) DeletePacket(conpkt);
  230.     if (conport) DeletePort(conport);
  231.     reqres();
  232.     if (IntuitionBase)
  233.     {
  234.         CloseLibrary(IntuitionBase);
  235.         IntuitionBase = NULL;
  236.     }
  237.  
  238.     /* reset standard I/O */
  239.     if (rawcon > 0)
  240.     {
  241.         /* restore Lattice AmigaDOS file handles */
  242.         DOSFH(0) = Input();
  243.         DOSFH(1) = Output();
  244.         DOSFH(2) = saverr;
  245. #ifdef LAT304
  246.         close(rawcon);
  247. #else
  248.         Close(rawcon);
  249. #endif
  250.     }
  251. }
  252.  
  253. /*
  254.  * reqoff -- turn requestors off
  255.  *    When AmigaDOS encounters an error that user intervention can fix
  256.  *    (like inserting the correct disk), it normally puts up a requestor.
  257.  *    The following code disables requestors, causing an error to be
  258.  *    returned instead.
  259.  */
  260. reqoff()
  261. {
  262.     pushwindow = CurProc->pr_WindowPtr;
  263.     CurProc->pr_WindowPtr = (APTR)-1;
  264. }
  265. /*
  266.  * reqpop -- restore requesters to action at last reqoff
  267.  */
  268. reqpop()
  269. {
  270.     CurProc->pr_WindowPtr = pushwindow;
  271. }
  272.  
  273. /*
  274.  * reqres -- restore requestors to startup action
  275.  */
  276. reqres()
  277. {
  278.     CurProc->pr_WindowPtr = savewindow;
  279. }
  280.  
  281. /*
  282.  * KillIO -- terminate an I/O request
  283.  */
  284. static int KillIO(iob)
  285. struct IORequest *iob;
  286. {
  287.     AbortIO(iob);
  288.     return(WaitIO(iob));
  289. }
  290.  
  291. /*
  292.  * DoIOQuick -- DoIO with quick IO
  293.  * This should not be used where waiting is expected since
  294.  *    it cannot be interrupted.
  295.  */
  296. static int DoIOQuick(iob)
  297. register struct IORequest *iob;
  298. {
  299.     register int D7Save;    /* V1.1 bug. IO sometimes trashes D7 */
  300.  
  301.     /* do I/O with quick option, wait around if necessary */
  302.     iob->io_Flags = IOF_QUICK;
  303.     if (BeginIO(iob) == 0 && !(iob->io_Flags & IOF_QUICK))
  304.         WaitIO(iob);
  305.  
  306.     /* return the error, if any */
  307.     return((int)iob->io_Error);
  308. }
  309.  
  310. /*
  311.  * ttopen -- open the serial device
  312.  *    If already open, returns 0 immediately.
  313.  *    Otherwise, the ttname is compare to SERIALNAME and used to
  314.  *    open the serial device, and, if the value of *lcl is < 0, it is
  315.  *    reset to 1 indicating local mode.  Returns -1 on error.
  316.  */
  317. ttopen(ttname, lcl, modem)
  318. char *ttname;
  319. int *lcl;
  320. int modem;
  321. {
  322.     register struct IOExtSer *iob = ReadIOB;
  323.  
  324.     if (serialopen) return(0);    /* ignore if already open */
  325.  
  326.     /* verify the serial name */
  327.     if (strcmp(ttname, SERIALNAME) != 0) return(-1);
  328.  
  329.     /* set open modes */
  330.     iob->io_SerFlags = (modem) ? (SERF_SHARED|SERF_7WIRE) : SERF_SHARED;
  331.  
  332.     /* open the serial device */
  333.     if (OpenDevice(ttname, 0L, iob, 0L) != 0) return(-1);
  334.     serialopen = TRUE;
  335.     pendread = pendwrite = pendconsole = FALSE;
  336.     queuedser = -1;
  337.  
  338.     /* fill in the fields of the other IO blocks */
  339.     *WriteIOB = *iob;
  340.  
  341.     /* set local mode */
  342.     if (*lcl == -1)    *lcl = 1; /* always local */
  343.     return(0);
  344. }
  345.  
  346. /*
  347.  * StartTimer -- start a timeout
  348.  */
  349. static VOID StartTimer(secs, micro)
  350. LONG secs, micro;
  351. {
  352.     TimerIOB->tr_node.io_Command = TR_ADDREQUEST;
  353.     TimerIOB->tr_time.tv_secs  = secs;
  354.     TimerIOB->tr_time.tv_micro = micro;
  355.     SendIO(TimerIOB);
  356. }
  357.  
  358. /*
  359.  * SerialWait -- wait for serial I/O to terminate
  360.  *    return I/O error
  361.  */
  362. static int SerialWait(iob, timeout)
  363. register struct IOExtSer *iob;
  364. int timeout;
  365. {
  366.     register int D7Save;        /* save register D7 */
  367.     register LONG sigs;
  368.     register struct timerequest *timer = TimerIOB;
  369.     register LONG waitsigs;
  370.  
  371.     /* set up timeout if necessary */
  372.     if (timeout > 0) StartTimer((LONG)timeout, 0L);
  373.  
  374.     /* wait for completion, timeout, or interrupt */
  375.     sigs = 0;
  376.     waitsigs = (1L << serport->mp_SigBit) | intsigs;
  377.     for (;;)
  378.     {
  379.         if (sigs & intsigs)
  380.         {    /* interrupted */
  381.             if (timeout > 0) KillIO(timer);
  382.             KillIO(iob);
  383.             testint(sigs);
  384.             return(-1);
  385.         }
  386.         if (CheckIO(iob))
  387.         {
  388.             if (timeout > 0) KillIO(timer);
  389.             return(WaitIO(iob));
  390.         }
  391.         if (timeout > 0 && CheckIO(timer))
  392.         {
  393.             KillIO(iob);
  394.             WaitIO(timer);
  395.             /* restart if XOFF'ed */
  396.             iob->IOSer.io_Command = CMD_START;
  397.             DoIOQuick(iob);
  398.             return(-1);
  399.         }
  400.         sigs = Wait(waitsigs);
  401.     }
  402. }
  403.  
  404. /*
  405.  * TerminateRead -- wait for queued read to finish
  406.  */
  407. static int TerminateRead()
  408. {
  409.     if (!pendread) return(0);
  410.     if (WaitIO(ReadIOB) == 0) queuedser = serbufc;
  411.     pendread = FALSE;
  412.     return((int)ReadIOB->IOSer.io_Error);
  413. }
  414.  
  415. /*
  416.  * TerminateWrite -- ensure WriteIOB is ready for reuse
  417.  */
  418. static int TerminateWrite(timeout)
  419. int timeout;
  420. {
  421.     testint(0L);
  422.     if (!pendwrite) return(0);
  423.     pendwrite = FALSE;
  424.     return(SerialWait(WriteIOB, timeout));
  425. }
  426.  
  427. /*
  428.  * SerialReset -- terminate pending serial and console I/O
  429.  */ 
  430. static VOID SerialReset()
  431. {
  432.     if (pendread)
  433.     {
  434.         AbortIO(ReadIOB); /* should work even if read finished */
  435.         TerminateRead();
  436.     }
  437.  
  438.     if (pendconsole)
  439.     {    /* this does not happen normally */
  440.         WaitPort(conport);
  441.         GetMsg(conport);
  442.         pendconsole = FALSE;
  443.     }
  444.  
  445.     if (pendwrite)
  446.         TerminateWrite(1);
  447. }
  448.  
  449. /*
  450.  * ttres -- reset serial device
  451.  */
  452. ttres()
  453. {
  454.     if (!serialopen) return(-1);
  455.  
  456.     /* reset everything */
  457.     SerialReset();
  458.     ReadIOB->IOSer.io_Command = CMD_RESET;
  459.     return(DoIOQuick(ReadIOB) ? -1 : 0);
  460. }
  461.  
  462. /*
  463.  * ttclos -- close the serial device
  464.  */
  465. ttclos()
  466. {
  467.     if (!serialopen) return(0);
  468.     if (ttres() < 0) return(-1);
  469.     CloseDevice(ReadIOB);
  470.     serialopen = FALSE;
  471.     return(0);
  472. }
  473.  
  474. /*
  475.  * tthang -- hang up phone line
  476.  *    Drops DTR by closing serial.device
  477.  */
  478. tthang()
  479. {    return((serialopen) ? ttclos() : -1); }
  480.  
  481. /*
  482.  * ttpkt -- set serial device up for packet transmission
  483.  *    sets serial parameters
  484.  */
  485. ttpkt(baud, flow)
  486. int baud, flow;
  487. {
  488.     extern UBYTE eol;
  489.     register struct IOExtSer *iob = ReadIOB;
  490.     int speed;
  491.  
  492.     if (!serialopen || pendread) return(-1);
  493.  
  494.     /* terminate any pending writes */
  495.     TerminateWrite(1);
  496.  
  497.     /* fill in parameters */
  498.     iob->io_CtlChar = 0x11130000;
  499.     if (baud >= 0 && (speed = ttsspd(baud)) >= 0) iob->io_Baud = speed;
  500.     setmem(&iob->io_TermArray, sizeof(struct IOTArray), eol);
  501.     iob->io_ReadLen = iob->io_WriteLen = 8;
  502.     iob->io_StopBits = 1;
  503.     if (flow)
  504.         iob->io_SerFlags &= ~SERF_XDISABLED;
  505.     else
  506.         iob->io_SerFlags |= SERF_XDISABLED;
  507.     /* if no flow and high baud rate, RAD_BOOGIE is appropriate */
  508.     if (!flow && iob->io_Baud > 19200)
  509.         iob->io_SerFlags |= SERF_RAD_BOOGIE;
  510.     else
  511.         iob->io_SerFlags &= ~SERF_RAD_BOOGIE;
  512.     iob->io_SerFlags &= ~(SERF_EOFMODE|SERF_PARTY_ON|SERF_PARTY_ODD);
  513.  
  514.     /* set the parameters */
  515.     iob->IOSer.io_Command = SDCMD_SETPARAMS;
  516.     if (DoIOQuick(iob) != 0) return(-1);
  517.     return(ttflui());
  518. }
  519.  
  520. /*
  521.  * ttvt -- set up serial device for connect mode
  522.  */
  523. ttvt(baud, flow)
  524. int baud, flow;
  525. {    return(ttpkt(baud, flow)); }
  526.  
  527. /*
  528.  * ttsspd -- verify baud rate
  529.  */
  530. int ttsspd(speed)
  531. {
  532.     if (speed < 110 || speed > 292000) return(-1);
  533.     return(max(112, speed));
  534. }
  535.  
  536. /*
  537.  * ttflui -- flush serial device input buffer
  538.  */
  539. ttflui()
  540. {
  541.     if (!serialopen || pendread) return(-1);
  542.     queuedser = -1;
  543.     ReadIOB->IOSer.io_Command = CMD_CLEAR;
  544.     return(DoIOQuick(ReadIOB) ? -1 : 0);
  545. }
  546.  
  547.  
  548. static struct IntuiText BodyText = {
  549.     -1, -1, 0, 4, 4, NULL, "Interrupt Requested", NULL
  550. };
  551.  
  552. static struct IntuiText ContinueText = {
  553.     -1, -1, 0, 4, 4, NULL, "Continue", NULL
  554. };
  555.  
  556. static struct IntuiText AbortText = {
  557.     -1, -1, 0, 4, 4, NULL, "Exit C-Kermit", NULL
  558. };
  559.  
  560. /*
  561.  * test for and catch interrupt
  562.  */
  563. testint(sigs)
  564. LONG sigs;
  565. {
  566.     int (*catch)();
  567.  
  568.     /* test for and reset caught interrupt signals */
  569.     if (((sigs | SetSignal(0L, (LONG)BREAKSIGS)) & intsigs) && inthdlr)
  570.     {
  571.         if (AutoRequest((struct Window *)NULL,
  572.                 &BodyText,
  573.                 &ContinueText,
  574.                 &AbortText,
  575.                 0L, 0L, 260L, 55L) )
  576.             return;
  577.         catch = inthdlr;
  578.         inthdlr = NULL;
  579.         intsigs = 0;
  580.         (*catch)();
  581.     }
  582. }
  583.  
  584. /*
  585.  * conint -- set console interrupt handler
  586.  */
  587. conint(newhdlr)
  588. int (*newhdlr)();
  589. {
  590.     testint(0L);            /* handle any pending interrupts */
  591.     inthdlr = newhdlr;        /* set the new handler */
  592.     intsigs = BREAKSIGS;        /* note signal caught */
  593. }
  594.  
  595. /*
  596.  * connoi -- disable interrupt trapping
  597.  */
  598. connoi()
  599. {
  600.     inthdlr = NULL;            /* disable interrupts */
  601.     intsigs = 0;            /* note signal ignored */
  602.     testint(0L);            /* ignore pending interrupts */
  603. }
  604.  
  605. /*
  606.  * ttchk -- return number of chars immediately available from serial device
  607.  */ 
  608. ttchk()
  609. {
  610.     register struct IOExtSer *read = ReadIOB;
  611.  
  612.     if (!serialopen) return(-1);
  613.     testint(0L);
  614.     if (pendread && !CheckIO(read)) return(0);
  615.     if (TerminateRead() != 0) return(-1);
  616.     read->IOSer.io_Command = SDCMD_QUERY;
  617.     return((DoIOQuick(read) == 0)
  618.             ? ((queuedser >= 0) + (int)read->IOSer.io_Actual)
  619.             : -1);
  620. }
  621.  
  622. /*
  623.  * ttxin -- get n characters from serial device
  624.  */
  625. ttxin(n, buf)
  626. int n;
  627. char *buf;
  628. {    return(ttinl(buf, n, 0, -1)); }
  629.  
  630. /*
  631.  * ttinc -- read character from serial line
  632.  */
  633. ttinc(timeout)
  634. int timeout;
  635. {
  636.     UBYTE ch;
  637.  
  638.     return((ttinl(&ch, 1, timeout, -1) > 0) ? (int)ch : -1);
  639. }
  640.  
  641. /*
  642.  * ttol -- write n chars to serial device
  643.  */
  644. ttol(buf, n)
  645. char *buf;
  646. int n;
  647. {
  648.     register int D7Save;
  649.     register struct IOExtSer *write = WriteIOB;
  650.  
  651.     if (!serialopen) return(-1);
  652.     if (TerminateWrite(0) != 0) return(-1);
  653.     pendwrite = TRUE;
  654.     write->IOSer.io_Command = CMD_WRITE;
  655.     write->IOSer.io_Data    = (APTR)buf;
  656.     write->IOSer.io_Length  = n;
  657.     SendIO(write);
  658.     return(n);
  659. }
  660.  
  661. /*
  662.  * ttoc -- output single character to serial device
  663.  */
  664. ttoc(c)
  665. char c;
  666. {    return(ttol(&c, 1)); }
  667.  
  668. /*
  669.  * ttinl -- read from serial device, possibly with timeout and eol character
  670.  *    reads up to n characters, returning the number of characters read
  671.  *    if eol >= 0, reading the eol character will terminate read
  672.  *    if timeout > 0, terminates read if timeout elapses
  673.  *    returns -1 on error, such as timeout or interrupt
  674.  */
  675. ttinl(buf, n, timeout, eol)
  676. register char *buf;
  677. int n;
  678. int timeout;                /* timeout in seconds or <= 0 */
  679. int eol;                /* end of line character */
  680. {
  681.     register int D7Save;
  682.     register struct IOExtSer *read = ReadIOB;
  683.     register int count;
  684.  
  685.     testint(0L);
  686.      if (!serialopen || pendread || n <= 0) return(-1);
  687.  
  688.     /* handle pushback */
  689.     if (queuedser >= 0)
  690.     {
  691.         *buf = queuedser;
  692.         queuedser = -1;
  693.         if (*buf == eol || n == 1) return(1);
  694.         ++buf;
  695.         --n;
  696.         count = 1;
  697.     }
  698.     else
  699.         count = 0;
  700.  
  701.     /* set up line terminator */
  702.     if (eol >= 0)
  703.     {
  704.         /* set up line terminator */
  705.         if (eol != *(UBYTE *)&read->io_TermArray)
  706.         {
  707.             setmem(&read->io_TermArray,
  708.                    sizeof(struct IOTArray), eol);
  709.             read->IOSer.io_Command = SDCMD_SETPARAMS;
  710.             DoIOQuick(read);
  711.         }
  712.         read->io_SerFlags |= SERF_EOFMODE;
  713.     }
  714.     else
  715.         read->io_SerFlags &= ~SERF_EOFMODE;
  716.  
  717.     /* set up the read */
  718.     read->IOSer.io_Command = CMD_READ;
  719.     read->IOSer.io_Data    = (APTR)buf;
  720.     read->IOSer.io_Length  = n;
  721.  
  722.     /* perform read quickly if possible */
  723.     read->IOSer.io_Flags = IOF_QUICK;
  724.     BeginIO(read);
  725.     if (read->IOSer.io_Flags & IOF_QUICK)
  726.     {
  727.         read->IOSer.io_Flags = 0;
  728.         return ((read->IOSer.io_Error == 0)
  729.             ? (count + (int)read->IOSer.io_Actual)
  730.             : -1);
  731.     }
  732.  
  733.     /* wait for read to complete */
  734.     return ((SerialWait(read, timeout) != 0)
  735.         ? -1
  736.         : count + (int)read->IOSer.io_Actual );
  737. }
  738.  
  739. /*
  740.  * Sleeper -- perform an interruptible timeout
  741.  */
  742. static Sleeper(secs, micro)
  743. LONG secs, micro;
  744. {
  745.     register int D7Save;
  746.     register LONG sigs;
  747.     register LONG waitsigs;
  748.     register struct timerequest *timer = TimerIOB;
  749.  
  750.     if (!timeropen) return(-1);
  751.     StartTimer(secs, micro);
  752.     sigs = 0;
  753.     waitsigs = (1L << serport->mp_SigBit) | intsigs;
  754.     for (;;)
  755.     {
  756.         if (CheckIO(timer))
  757.         {
  758.             WaitIO(timer);
  759.             return(0);
  760.         }
  761.         if (sigs & intsigs)
  762.         {
  763.             KillIO(timer);
  764.             testint(sigs);
  765.             return(-1);
  766.         }
  767.         sigs = Wait(waitsigs);
  768.     }
  769. }
  770.  
  771. /*
  772.  * sleep -- wait n seconds
  773.  */
  774. sleep(n)
  775. int n;
  776. {    return(Sleeper((LONG)n, 0L)); }
  777.  
  778. /*
  779.  * msleep -- wait n milliseconds
  780.  */
  781. msleep(m)
  782. int m;
  783. {    return(Sleeper((LONG)(m / 1000), (m % 1000) * 1000L)); } 
  784.  
  785.  
  786. /*
  787.  * rtimer -- reset elapsed time
  788.  */
  789. rtimer()
  790. {    DateStamp(&prevtime); }
  791.  
  792. /*
  793.  * gtimer -- get currently elapsed time in seconds
  794.  */
  795. gtimer()
  796. {
  797.     int x;
  798.     struct DateStamp curtime;
  799.  
  800.     DateStamp(&curtime);
  801.     x = ((curtime.ds_Days   - prevtime.ds_Days  ) * 1440 +
  802.          (curtime.ds_Minute - prevtime.ds_Minute) ) * 60 +
  803.          (curtime.ds_Tick   - prevtime.ds_Tick  ) / 50;
  804.     return((x < 0) ? 0 : x );
  805. }
  806.  
  807. /*
  808.  * ztime -- format current date and time into string
  809.  */
  810. ztime(s)
  811. char **s;
  812. {
  813.    /*
  814.     * The following date code taken from a USENET article by
  815.     *    Tomas Rokicki(rokicki@Navajo.ARPA)
  816.     */
  817.    static char *months[] = { NULL,
  818.       "January","February","March","April","May","June",
  819.       "July","August","September","October","November","December"};
  820.    static char buf[32];
  821.  
  822.    long n ;
  823.    int m, d, y ;
  824.    struct DateStamp datetime;
  825.  
  826.    DateStamp(&datetime);
  827.  
  828.    n = datetime.ds_Days - 2251 ;
  829.    y = (4 * n + 3) / 1461 ;
  830.    n -= 1461 * y / 4 ;
  831.    y += 1984 ;
  832.    m = (5 * n + 2) / 153 ;
  833.    d = n - (153 * m + 2) / 5 + 1 ;
  834.    m += 3 ;
  835.    if (m > 12) {
  836.       y++ ;
  837.       m -= 12 ;
  838.    }
  839.    sprintf(buf, "%02d:%02d:%02d %s %d, %d",
  840.            datetime.ds_Minute / 60, datetime.ds_Minute % 60,
  841.        datetime.ds_Tick / 50, months[m], d, y) ;
  842.    *s = buf;
  843. }
  844.  
  845. /*
  846.  * congm -- save console modes
  847.  */
  848. congm()
  849. {
  850.     if (!saverr) saverr = DOSFH(2);
  851.     return(0);
  852. }
  853.  
  854. /*
  855.  * CreateWindow -- create window and jam it into standard I/O
  856.  */
  857. int CreateWindow(esc)
  858. {
  859.     if (rawcon > 0) return(0);
  860.     congm();
  861.  
  862. #ifdef LAT304
  863.     if ((rawcon = open("RAW:0/0/640/200/Kermit", O_RDWR)) <= 0)
  864.         return(-1);
  865. #else
  866.     if ((rawcon = Open("RAW:0/0/640/200/Kermit", (LONG)MODE_NEWFILE)) == 0)
  867.         return(-1);
  868. #endif
  869.     DOSFH(0) = DOSFH(1) = DOSFH(2) = rawcon;
  870.  
  871.     /* if we create a window, don't abort on errors or echo */
  872.     backgrd = FALSE;
  873.     ckxech = 1;
  874.     return(0);
  875. }
  876.  
  877. /*
  878.  * concb -- put console in single character wakeup mode
  879.  */
  880. concb(esc)
  881. {
  882.     if (rawcon) return(0);
  883.     if (CurCLI && CurProc->pr_CIS != CurCLI->cli_StandardInput)
  884.         return(0);
  885.     return(CreateWindow(esc));
  886. }
  887.  
  888. /*
  889.  * conbin -- put console in raw mode
  890.  */
  891. conbin(esc)
  892. {
  893.     if (rawcon) return(0);
  894.     if (CurCLI && CurProc->pr_CIS != CurCLI->cli_StandardInput)
  895.         return(isatty(0) ? 0 : -1);
  896.     return(CreateWindow(esc));
  897. }
  898.  
  899. /*
  900.  * conres -- restore console
  901.  *    we actually restore in syscleanup()
  902.  */
  903. conres()
  904. {    return(0); }
  905.  
  906. /*
  907.  * conoc -- output character to console
  908.  */
  909. conoc(c)
  910. {
  911.     putchar(c);
  912.     fflush(stdout);
  913.     testint(0L);
  914. }
  915.  
  916. /*
  917.  * conxo -- output x chars to console
  918.  */ 
  919. conxo(n, buf)
  920. char *buf;
  921. int n;
  922. {
  923.     fflush(stdout);
  924.     write(FILENO(1), buf, n);
  925.     testint(0L);
  926. }
  927.  
  928. /*
  929.  * conol -- output line to console
  930.  */
  931. conol(l)
  932. char *l;
  933. {
  934.     fputs(l, stdout);
  935.     fflush(stdout);
  936.     testint(0L);
  937. }
  938.  
  939. /*
  940.  * conola -- output line array to console
  941.  */
  942. conola(l)
  943. char **l;
  944. {
  945.     for (; **l; ++l) conol(*l);
  946. }
  947.  
  948. /*
  949.  * conoll -- output line with CRLF
  950.  */
  951. conoll(l) char *l;
  952. {
  953.     conol(l);
  954.     conxo(2, "\r\n");
  955. }
  956.  
  957. /*
  958.  * conchk -- returns nonzero if characters available from console
  959.  */
  960. conchk()
  961. {
  962.     fflush(stdout);
  963.     testint(0L);
  964.     return(WaitForChar(DOSFH(0), 0L) != 0);
  965. }
  966.  
  967. /*
  968.  * coninc -- get input character from console
  969.  */
  970. coninc(timeout)
  971. int timeout;
  972. {
  973.     UBYTE ch;
  974.  
  975.     fflush(stdout);
  976.     testint(0L);
  977.     if (timeout > 0 && !WaitForChar(DOSFH(0), timeout * 1000000L))
  978.         return(-1);
  979.     if (read(FILENO(0), &ch, 1) < 1) return(-1);
  980.     testint(0L);
  981.     return((int)ch);
  982. }
  983.  
  984. /*
  985.  * ttsndb -- send a BREAK
  986.  *    flushes queued and active output
  987.  */
  988. ttsndb()
  989. {
  990.     register int D7Save;
  991.  
  992.     if (!serialopen) return(-1);
  993.     /* flush queued output */
  994.     TerminateWrite(1);
  995.     nttoq = 0;
  996.     pendwrite = TRUE;
  997.     WriteIOB->IOSer.io_Command = SDCMD_BREAK;
  998.     WriteIOB->io_SerFlags &= ~SERF_QUEUEDBRK;
  999.     SendIO(WriteIOB);
  1000.     return(0);
  1001. }
  1002.  
  1003. /*
  1004.  * ttocq -- write char to serial device, queueing if necessary
  1005.  *    returns -2 on overrun, -1 on serial error
  1006.  *    use only in connect mode
  1007.  */
  1008. ttocq(c)
  1009. char c;
  1010. {
  1011.     register int i;
  1012.  
  1013.     if (!serialopen) return(-1);
  1014.     if (pendwrite && CheckIO(WriteIOB))
  1015.     {
  1016.         pendwrite = FALSE;
  1017.         if (WaitIO(WriteIOB) != 0) return(-1);
  1018.     }
  1019.     if (pendwrite)
  1020.     {
  1021.         if (nttoq >= NTTOQ) return(-2);        /* overrun */
  1022.         ttoq[(pttoq + nttoq++) % NTTOQ] = c;
  1023.     }
  1024.     else if (nttoq == 0)
  1025.         return(ttoc(c));
  1026.     else
  1027.     {
  1028.         i = ttoc(ttoq[pttoq]);
  1029.         ttoq[(pttoq + nttoq) % NTTOQ] = c;
  1030.         pttoq = (pttoq + 1) % NTTOQ;
  1031.         if (i < 0) return(-1);
  1032.     }
  1033.     return(1);
  1034. }
  1035.  
  1036. /*
  1037.  * ttonq -- returns number of characters in serial output queue
  1038.  */
  1039. int ttonq()
  1040. {    return(nttoq); }
  1041.  
  1042. /*
  1043.  * conttb -- prepare for contti() usage
  1044.  */
  1045. conttb()
  1046. {
  1047.     /* flush queued input and output */
  1048.     queuedcon = -1;
  1049.     pttoq = nttoq = 0;
  1050. }
  1051.  
  1052. /*
  1053.  * contte -- end contti() usage
  1054.  *    this can be called after a tthang, it which case ttres will already
  1055.  *    have done this cleanup
  1056.  */
  1057. contte()
  1058. {
  1059.     /* clear any pending ^C, ^D interrupts */
  1060.     testint(0L);
  1061.  
  1062.     /* terminate any pending I/O */
  1063.     if (serialopen) SerialReset();
  1064. }
  1065.  
  1066. /*
  1067.  * contti -- wait for console or tty input
  1068.  *    returns next console input or -1 when serial input available
  1069.  */
  1070. int contti()
  1071. {
  1072.     register int D7Save;
  1073.     register int i;
  1074.     register LONG waitsigs;
  1075.     register struct DosPacket *pkt = conpkt;
  1076.     register struct IOExtSer *read = ReadIOB;
  1077.     static UBYTE conchar;
  1078.     BPTR dosfh = DOSFH(0);
  1079.     struct FileHandle *fh = (struct FileHandle *)BADDR(dosfh);
  1080.  
  1081.     if (queuedcon >= 0)
  1082.     {
  1083.         conchar = queuedcon;
  1084.         queuedcon = -1;
  1085.         return((int)conchar);
  1086.     }
  1087.  
  1088.     if (!pendconsole)
  1089.     {    /* start a console read */
  1090.         pkt->dp_Port = conport;
  1091.         pkt->dp_Type = ACTION_READ;
  1092.         pkt->dp_Arg1 = (LONG)dosfh;
  1093.         pkt->dp_Arg2 = (LONG)&conchar;
  1094.         pkt->dp_Arg3 = 1;
  1095.         PutMsg(fh->fh_Process, pkt->dp_Link);
  1096.         pendconsole = TRUE;
  1097.     }
  1098.  
  1099.     if (queuedser < 0 && !pendread)
  1100.     {    /* start a serial read */
  1101.         read->IOSer.io_Command = CMD_READ;
  1102.         read->IOSer.io_Data    = (APTR)&serbufc;
  1103.         read->IOSer.io_Length  = 1;
  1104.         SendIO(read);
  1105.         pendread = TRUE;
  1106.     }
  1107.  
  1108.     waitsigs = (1L << serport->mp_SigBit) | (1L << conport->mp_SigBit);
  1109.     for (;;)
  1110.     {
  1111.         if (pendwrite && CheckIO(WriteIOB))
  1112.         {
  1113.             pendwrite = FALSE;
  1114.             if (nttoq > 0)
  1115.             {
  1116.                 i = ttoc(ttoq[pttoq]);
  1117.                 pttoq = (pttoq + 1) % NTTOQ;
  1118.                 --nttoq;
  1119.                 if (i < 0) return(-1);
  1120.             }
  1121.         }
  1122.  
  1123.         /* give the console first chance */
  1124.         if (GetMsg(conport))
  1125.         {
  1126.             pendconsole = FALSE;
  1127.             if (pkt->dp_Res1 != 1) return(-1);
  1128.             /* translate CSI to ESC [ */
  1129.             if (conchar == 0x9B)
  1130.             {    conchar = 0x1B; queuedcon = '['; }
  1131.             return((int)conchar);
  1132.         }
  1133.  
  1134.         if (queuedser >= 0) return(-2);
  1135.  
  1136.         if (CheckIO(read))
  1137.             return((TerminateRead() == 0) ? -2 : -1);
  1138.  
  1139.         Wait(waitsigs);
  1140.     }
  1141. }
  1142.